package com.zip4j;

import com.github.junrar.Archive;
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.model.FileHeader;
import org.apache.commons.lang3.time.StopWatch;

import java.io.File;
import java.io.FileOutputStream;
import java.nio.charset.Charset;
import java.util.List;

import static java.nio.charset.StandardCharsets.UTF_8;

public class UnPackeUtil {

  public static Charset gbk = Charset.forName("GBK");

    public static String unpack(String source, String targetPath){
        File file = new File(source);
        String name = file.getName();

        String suffix = name.substring(name.lastIndexOf(".") + 1);
        String prefix = name.substring(0, name.lastIndexOf("."));
        if ("zip".equalsIgnoreCase(suffix)){
            //如果是 zip 格式
            unPackZip(file, ZipFileUntil.ZIP_PS, targetPath +prefix);
        }else if ("rar".equals(suffix.toLowerCase())){
            //如果是 rar 格式
            unPackRar(file, targetPath +prefix);
        }else{
            return null;
        }
        return targetPath +prefix;
    }

    private static void unPackZip(File zipFile, String password, String destPath) {
        unPackZip(zipFile,password,destPath, UTF_8 );
    }
    /**
     * zip文件解压
     *
     * @param destPath 解压文件路径
     * @param zipFile  压缩文件
     * @param password 解压密码(如果有)
     */
    private static void unPackZip(File zipFile, String password, String destPath,Charset charset ) {
        try (ZipFile zip = new ZipFile(zipFile)) {
            zip.setCharset(charset);
            List<FileHeader> headers = zip.getFileHeaders();
            if (!gbk.equals(charset)&&isRandomCode(headers)) {
                //判断文件名是否有乱码，有乱码，将编码格式设置成GBK
                 unPackZip(zipFile,password,destPath, gbk );
                return;
            }
            StopWatch started = StopWatch.createStarted();
            if (zip.isEncrypted()) {
                // 如果解压需要密码
                if (password == null) {
                    throw new RuntimeException("压缩包已加密");
                }
                zip.setPassword(password.toCharArray());
            }
            System.out.println("begin unpack zip file....");
            zip.extractAll(destPath);

            System.out.println("end unpack zip file");
        } catch (Exception e) {
            throw new RuntimeException("文件解压失败" + e.getMessage());
        }
    }

    //待解压的文件名是否乱码
    private static boolean isRandomCode(List<FileHeader> fileHeaders) {
        for (int i = 0; i < fileHeaders.size(); i++) {
            FileHeader fileHeader = fileHeaders.get(i);
            boolean canEnCode = gbk.newEncoder().canEncode(fileHeader.getFileName());
            if (!canEnCode) {//canEnCode为true，表示不是乱码。false.表示乱码。是乱码则需要重新设置编码格式
                return true;
            }
        }
        return false;
    }

    /**
     * rar文件解压(不支持有密码的压缩包)
     *
     * @param rarFile  rar压缩包
     * @param destPath 解压保存路径
     */
    private static void unPackRar(File rarFile, String destPath) {
        try (Archive archive = new Archive(rarFile)) {
            if (null != archive) {
                com.github.junrar.rarfile.FileHeader fileHeader = archive.nextFileHeader();
                File file = null;
                while (null != fileHeader) {
                    // 防止文件名中文乱码问题的处理
                    String fileName = fileHeader.getFileNameW().isEmpty() ? fileHeader.getFileNameString() : fileHeader.getFileNameW();
                    if (fileHeader.isDirectory()) {
                        //是文件夹
                        file = new File(destPath + File.separator + fileName);
                        file.mkdirs();
                    } else {
                        //不是文件夹
                        file = new File(destPath + File.separator + fileName.trim());
                        if (!file.exists()) {
                            if (!file.getParentFile().exists()) {
                                // 相对路径可能多级，可能需要创建父目录.
                                file.getParentFile().mkdirs();
                            }
                            file.createNewFile();
                        }
                        try (FileOutputStream os = new FileOutputStream(file)){
                            archive.extractFile(fileHeader, os);
                        }
                    }
                    fileHeader = archive.nextFileHeader();
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("文件解压失败" + e.getMessage());
        }
    }
}
